﻿#ifndef RESOURCE_MANAGER_H
#define RESOURCE_MANAGER_H

#include <map>
#include <unordered_map>
#include <string>

#include "Scene/Mesh.h"
#include "Renderer/shader.h"

namespace CC{
// A static singleton ResourceManager class that hosts several
// functions to load Textures and Shaders. Each loaded texture
// and/or shader is also stored for future reference by string
// handles. All functions and resources are static and no 
// public constructor is defined.
    class Entity;
class ResourceManager
{
public:
    // resource storage
    

    // loads (and generates) a shader program from file loading vertex, fragment (and geometry) shader's source code. If gShaderFile is not nullptr, it also loads a geometry shader
     static Shader*    LoadShader(std::string name, const char *vShaderFile, const char *fShaderFile);
    // retrieves a stored sader
     static Shader*    GetShader(std::string name);
    // loads (and generates) a texture from file
    static Texture2D* LoadTexture(const std::string file, std::string name, TextureType type=TextureType_ClampToEdge);
    static Texture2D* LoadTextureSync(const std::string file, std::string name, Entity* entity, std::function<void(Entity* e, Texture2D* t)> callback, TextureType type = TextureType_ClampToEdge);
    // retrieves a stored texture
    static Texture2D* GetTexture(std::string name);

    static unsigned char* LoadStbFunction(char const *filename, int &x, int &y, int &channels_in_file, int desired_channels);

    // loads (and generates) a texture from file
     static TextureCube* LoadTextureCube(std::vector<std::string>& files, std::string name);
    // retrieves a stored texture
     static TextureCube* GetTextureCube(std::string name);

    // loads (and generates) a texture from file
    // static Texture3D& LoadTexture3D(const char *file, std::string name);
    // retrieves a stored texture
    // static Texture3D& GetTexture3D(std::string name);

    // static Font& LoadFont(const char *file, std::string name);
    // static Font& GetFont(std::string name);

    // static Character& LoadCharacter(Font& font, std::string name, unsigned int fontSize);
    // static Character& GetCharacter(std::string name);

    static Model* LoadModel(const char *file, std::string name, TextureType textureType = TextureType_ClampToEdge);
    static Model* LoadModelSync(const char *file, std::string name, Entity* entity, std::function<void(Entity* e, Model* m)> callback, TextureType textureType = TextureType_ClampToEdge);
    static Model* GetModel(std::string name);

    // properly de-allocates all loaded resources
    static void      Clear();

    static void      ClearTexture(const char* name);

//    static void ClearTextureGL(std::string name);
private:
    // private constructor, that is we do not want any actual resource manager objects. Its members and functions should be publicly available (static).
    ResourceManager() { }
    // loads and generates a shader from file
//     static Shader    loadShaderFromFile(const char *vShaderFile, const char *fShaderFile, const char *gShaderFile = nullptr);
//     // loads a single texture from file
//     static Texture2D loadTextureFromFile(const char *file, bool alpha=true);
//     static Texture3D loadTexture3DFromFile(const char *file, bool alpha=true);

//     static Texture2D loadTextureFontFromFile(Font& font);

//     static Model* loadModelFromFile(const char *file);

// //    static Animator* loadAnimatorFromFile(const char *file, Model& model);

//     static std::vector<Texture2D> loadMaterialTextures(aiMaterial *mat, aiTextureType type, std::string typeName);
//     static Material loadMaterialWithoutTextures(aiMaterial *mat);
//     //static Model* parseObj(std::vector<std::string>& data);

//     //static std::vector<std::string> readFile(const char *file);

//     static void processNode(aiNode *node, const aiScene *scene, Model& model);

//     static Mesh processMesh(aiMesh *mesh, const aiScene *scene, Model& model);

//     static void extractBoneWeightForVertices(std::vector<Vertex>& vertices, aiMesh* mesh, const aiScene* scene, Model& model);

//     static void setVertexBoneData(Vertex& vertex, int boneID, float weight);

//     static void setVertexBoneDataToDefault(Vertex& vertex);
};
}
#endif
